home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1998 March / Macworld (1998-03) (Disk 1).dmg / Shareware World / Utilities / Text Processing / Alpha / Tcl / Packages / Docprojects.tcl < prev    next >
Encoding:
Text File  |  1997-12-12  |  29.7 KB  |  974 lines  |  [TEXT/ALFA]

  1. ## -*-Tcl-*-
  2.  # ###################################################################
  3.  #  Vince's Additions - an extension package for Alpha
  4.  # 
  5.  #  FILE: "Docprojects.tcl"
  6.  #                                    created: 29/7/97 {4:59:22 pm} 
  7.  #                                last update: 12/12/97 {4:01:25 pm} 
  8.  #  Author: Vince Darley
  9.  #  E-mail: <darley@fas.harvard.edu>
  10.  #    mail: Division of Engineering and Applied Sciences, Harvard University
  11.  #          Oxford Street, Cambridge MA 02138, USA
  12.  #     www: <http://www.fas.harvard.edu/~darley/>
  13.  #  
  14.  # Copyright (c) 1997  Vince Darley
  15.  # 
  16.  # See the file "license.terms" for information on usage and redistribution
  17.  # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  18.  # ###################################################################
  19.  ##
  20.  
  21. alpha::extension documentProjects 1.5.2 {
  22.     alpha::package require Alpha 7.0b4
  23.     namespace eval Docproj {}
  24.     # dummy value
  25.     ensureset docProject(name) [list "None" "Project2" "Thesis"]
  26.     newPref var currentProject "None" Docproj "" docProject(name) "varitem"
  27.     menu::buildProc "Current Project" \
  28.       {menu::buildFlagMenu "Current Project" list currentProject DocprojmodeVars}
  29.     menu::insert global submenu 5 {Current Project}
  30.     menu::insert global items 5 \
  31.         "documentProjectPrefs…" "userDetails…" \
  32.         "<E<SremoveDocumentTemplate…" "<S<BeditDocumentTemplate…" \
  33.         "<SnewDocumentTemplate…" \
  34.         "<E<SremoveProject…" "<S<BeditProject…" "<SnewProject…"
  35.     newPref binding updateFileVersion "/f<U" Docproj
  36.     menu::insert winUtils items end \
  37.         "showInFinder" \
  38.         "(-" \
  39.         "updateDate" \
  40.         "[menu::bind DocprojmodeVars(updateFileVersion) -]"
  41.     lunion elec::MenuTemplates "createHeader" "newDocument"
  42.     catch "unbind F1 bind::Completion"
  43.     menu::insert elec items end \
  44.         {menu -n FunctionComments -p menu::generalProc {
  45.         "/eusual"    
  46.         "/e<Isimple" 
  47.         "/e<OwithAuthor" 
  48.         "/e<Uupdate" 
  49.     }}
  50.     set "newDocument::handlers(Document Projects)" Docproj::newHandler
  51.     # Use this simple proc if we don't have the newDocument package.
  52.     if {![alpha::package exists newDocument]} {
  53.         ;proc file::newDocument {} {
  54.             beep
  55.             Docproj::newHandler [list -n [statusPrompt "New doc name:"]]
  56.         }
  57.     } else {
  58.         alpha::package require newDocument
  59.     }
  60.     
  61.     # new document templates mode specific (useful if you have lots of templates)
  62.     newPref flag docTemplatesModeSpecific 1 Docproj
  63.     # Do we auto-update the header    of a file? 
  64.     newPref flag autoUpdateHeader 1 Docproj
  65.     # call on saveHook
  66.     proc Docproj::changeProject {name} {
  67.         if {$name == "*"} { return }
  68.         menu::flagProc "Current Project" $name
  69.     }
  70.     
  71.     # call on saveHook
  72.     hook::register saveHook updateHeaderHook
  73. } maintainer {
  74.     "Vince Darley" darley@fas.harvard.edu <http://www.fas.harvard.edu/~darley/>
  75. } uninstall {this-file} help {file "Documentprojects Help"}
  76.  
  77. # user projects
  78. if ![info exists docProject(addendum)] {
  79.     set docProject(addendum) { {none} {about some other stuff} {deep problems}}
  80.     set docProject(default_modes) { {} {C++ Tcl} {TeX}}
  81.     set docProject(extra) [list "" "Freely distributable" "Copyright (C) 1997 the author."]
  82.     set docProject(license) [list "" "" ""]
  83. }
  84.  
  85.  
  86. proc updateHeaderHook name {
  87.     global DocprojmodeVars
  88.     if $DocprojmodeVars(autoUpdateHeader) {
  89.         # update does no harm if it fails so we call it for all
  90.         # modes with no worries.
  91.         getWinInfo -w $name a
  92.         if $a(dirty) {
  93.             file::updateDate $name
  94.         }
  95.     }
  96. }
  97.  
  98. # header/source templates (NOTE: FORMAT OF THIS LIST MAY CHANGE)
  99. llunion elec::DocTemplates 1 \
  100.     { * "Empty" * "" *} \
  101.     { * "Default" * t_default *} \
  102.     { TeX "Basic LaTeX document" "None" t_latex * {article report letter book slides}} \
  103.     { C++ "Basic C++ header file" "Header" t_cpp_header * } \
  104.     { C++ "Basic C++ source file" "Source" t_cpp_source * } \
  105.     { HTML "HTML document" * t_html * } 
  106.     ## 
  107.      # \
  108.      # { C++ "Cpptcl Class Source" Source t_cpptcl_source "Cpptcl"} \
  109.      # { C++ "Cpptcl Class Header" Header t_cpptcl_header "Cpptcl"} \
  110.      # { Tcl "Itcl Class" * t_itcl_class "Cpptcl"}  \
  111.      # { Tcl "Blank Tcl Header" Header "\#" "Vince's Additions"} \
  112.      # { C++ "EvoX Class Source" Source t_cpptcl_source "EvoX"} \
  113.      # { C++ "EvoX Class Header" Header t_cpptcl_header "EvoX"}
  114.      ##
  115.  
  116. # used for file description headers
  117. if $synchroniseWithInternetConfig {
  118.     catch {set user(author) [icGetPref RealName]}
  119.     catch {set user(email) "<[icGetPref Email]>"}
  120.     catch {set user(www) "<[icGetPref WWWHomePage]>"}
  121.     catch {set user(organisation) [icGetPref Organization]}
  122. ensureset user(author) "Ken McKen"
  123. ensureset user(email) "ken@kenny.com"
  124. ensureset user(www) "http://www.kenny.com/"
  125. ensureset user(organisation) "Ken Corp."
  126.  
  127. ensureset user(address) "Rose St, MA 02143, USA"
  128. ensureset user(author_initials) "VMD"
  129.  
  130. ## 
  131.  # ###################################################################
  132.  #    Used to be "docProjEngine.tcl", now one file:
  133.  # ###################################################################
  134.  ##
  135.  
  136. proc global::userDetails {} {
  137.     dialog::pkg_options "Docprojects" \
  138.         "User Details (some maye be from Internet Config)" 1 user
  139. }
  140. proc global::documentProjectPrefs {} {
  141.     dialog::pkg_options "Docproj" "Preferences for your Document Projects"
  142. }
  143.  
  144. proc Docproj::newHandler {args} {
  145.     set doc [file::createDocument "new $args"]
  146.     if {[getModifiers] & 72} {
  147.         file::pickProject
  148.     }
  149.     file::createHeader $doc
  150.     return ""
  151. }
  152.  
  153. proc file::pickProject {} {
  154.     global DocprojmodeVars docProject
  155.     set item [listpick -p "Pick a project…" -L $DocprojmodeVars(currentProject) \
  156.         $docProject(name)]
  157.     if {$item != ""} { Docproj::changeProject $item }
  158.     return $item
  159. }
  160.  
  161. proc file::projectName {} { 
  162.     global DocprojmodeVars
  163.     return $DocprojmodeVars(currentProject)
  164. }
  165.  
  166. proc file::projectAddendum {} {
  167.     global docProject DocprojmodeVars
  168.     return [lindex $docProject(addendum) \
  169.         [lsearch -exact $docProject(name) $DocprojmodeVars(currentProject)]]
  170. }
  171.  
  172. proc file::projectExtra {} {
  173.     global docProject DocprojmodeVars
  174.     return [lindex $docProject(extra) \
  175.         [lsearch -exact $docProject(name) $DocprojmodeVars(currentProject)]]
  176. }
  177. proc file::projectLicense {} {
  178.     global docProject DocprojmodeVars
  179.     set ret [lindex $docProject(license) \
  180.         [lsearch -exact $docProject(name) $DocprojmodeVars(currentProject)]]
  181.     if {$ret == ""} {
  182.         return "none"
  183.     } else {
  184.         return $ret
  185.     }
  186. }
  187.  
  188. namespace eval functioncomments {}
  189.  
  190. ## 
  191.  # ----------------------------------------------------------------------
  192.  #     
  193.  #    "file::functionComment" --
  194.  #    
  195.  #     This procedure    generates a    nice little    comment    box
  196.  #     like this one here.
  197.  #    
  198.  #    Results:
  199.  #     Well it doesn't return    anything, but it allows    you    to
  200.  #     enter each    item simply, moving    from one to the next with Tab
  201.  #    
  202.  #    Side effects:
  203.  #     Not much
  204.  #    
  205.  # ----------------------------------------------------------------------
  206.  ##
  207. proc functioncomments::usual { {simple ""} {author 0} } {
  208.     global user
  209.     set fn [getSelect]
  210.     set fn [lindex $fn end]
  211.     beginningOfLine
  212.     set t "-------------------------------------------------------------------------\r"
  213.     append t "\r"
  214.     append t "\"$fn\" --\r"
  215.     append t "\r •description•\r"
  216.     if { $simple != "simple" } {
  217.         append t "\rResults:\r •results•\r\rSide effects:\r •side effects•\r"
  218.     }
  219.     if $author {
  220.         append t "\r--Version--Author------------------Changes-------------------------------"
  221.         append t "\r   1.0     $user(email) original\r"
  222.     }
  223.     append t "-------------------------------------------------------------------------"
  224.     set t [file::commentTextBlock $t]
  225.     elec::CenterInsertion $t
  226. }
  227.  
  228. proc functioncomments::simple {} { return [functioncomments::usual simple 0]}
  229. proc functioncomments::withAuthor {} { return [functioncomments::usual "" 1] }
  230.  
  231. proc file::commentTextBlock {text} {
  232.     set cc [commentCharacters "Paragraph"]
  233.     set c [lindex $cc 2]
  234.     regsub -all "(\r|\n)" $text "\r${c}" text
  235.     return "[lindex $cc 0]\r[lindex $cc 2]${text}\r[lindex $cc 1]\r"
  236. }
  237.  
  238. ## 
  239.  # -------------------------------------------------------------------------
  240.  #     
  241.  #    "file::functionCommentUpdate" --
  242.  #    
  243.  #     Handles updating of a version line    like the one below
  244.  #    
  245.  # --Version--Author------------------Changes-------------------------------  
  246.  #      1.0      <darley@fas.harvard.edu> original
  247.  #    1.1     <darley@fas.harvard.edu> quickly updated with shift-F1
  248.  # -------------------------------------------------------------------------
  249.  ##
  250. proc functioncomments::update {} {
  251.     global user
  252.     set begin [lindex [commentCharacters Paragraph] 2]
  253.     goto [file::findLocally "${begin}--Version--Author"]
  254.     goto [nextLineStart [nextLineStart [getPos] ]]
  255.     goto [file::findLocally "${begin}-------"]
  256.     elec::Insertion "${begin}   •Version•     $user(email) •Changes•\r"
  257. }
  258.  
  259. ## 
  260.  # -------------------------------------------------------------------------
  261.  #     
  262.  #    "file::findLocally" --
  263.  #    
  264.  #     Looks around for a    particular sequence    of characters (or a    regexp)
  265.  #     and returns the start of the closest fit, either fowards or backwards,
  266.  #     or    "" if no match was found.
  267.  # -------------------------------------------------------------------------
  268.  ##
  269. proc file::findLocally { chars {regexp 0} { pos "" } } {
  270.     if { $pos == "" } { set pos [getPos] }
  271.     
  272.     set found1 [lindex [search -s -f 0 -n -r $regexp -- "$chars" $pos] 0]
  273.     set found2 [lindex [search -s -f 1 -n -r $regexp -- "$chars" $pos] 0]
  274.     
  275.     if { $found1 != "" && $found2 != "" } { 
  276.         if [expr ($pos - $found1) <= ($found2 - $pos) ] {
  277.             return $found1
  278.         } else {
  279.             return $found2
  280.         }
  281.     }
  282.     
  283.     # return whatever we can, possibly ""
  284.     if { $found1 != "" } {
  285.         return $found1
  286.     } else {
  287.         if { $found2 == "" } { 
  288.             message "Couldn't find: $chars"
  289.         }
  290.         return $found2
  291.     }
  292. }
  293.  
  294.  
  295. ## 
  296.  # -------------------------------------------------------------------------
  297.  #     
  298.  #    "file::updateFileVersion"    --
  299.  #    
  300.  #     Update    the    version    number and information in the header block
  301.  #     of    a file.  Copes with both my old and new formats.
  302.  #    
  303.  # -------------------------------------------------------------------------
  304.  ##
  305. proc file::updateFileVersion {} {
  306.     global user
  307.     # in case the user wishes to return quickly
  308.     pushPosition
  309.     
  310.     goto 0
  311.     set begin [lindex [commentCharacters Paragraph] 2]
  312.     set pos [file::findLocally "_/_/_" 0]
  313.     if { $pos == "" || $pos > 1000 } {
  314.         set srch [quote::WhitespaceReg [quote::Regfind "${begin} " ]]
  315.         append srch {[0-9]+/[0-9]+/[0-9]+}
  316.         set pos [file::findLocally $srch 1]
  317.         if { $pos == "" } {
  318.             message "Couldn't find original version template."
  319.             set srch [quote::Regfind "${begin} "]
  320.             append srch "See header file for further information"
  321.             set pos [file::findLocally [quote::WhitespaceReg $srch]]
  322.             if { $pos != "" } {
  323.                 set pos [nextLineStart $pos]
  324.             } else {
  325.                 goto 0
  326.                 set pos [file::findLocally "${begin}\#\#\#"]
  327.                 if { $pos == "" } { message "Couldn't find any header" ; return }
  328.                 set pos [lindex [search -s -f 1 -n -- "${begin}\#\#\#" [nextLineStart $pos]] 0]
  329.                 if { $pos == "" } { message "Couldn't find any header" ; return }
  330.             }
  331.             goto $pos
  332.             set t  "${begin}\r"
  333.             append t  "${begin} modified by  rev reason\r"
  334.             append t  "${begin} -------- --- --- -----------\r"
  335.             append t  "${begin} [file::paddedDate] $user(author_initials) 1.0 original\r"
  336.             insertText $t
  337.             select $pos [getPos]
  338.             return ""
  339.         } else {
  340.             # This is the normal case.
  341.             # Find the last version number
  342.             set p -1
  343.             while { $p != $pos } {
  344.                 set pos $p
  345.                 set p [file::findLocally $srch 1 [nextLineStart $p] ]
  346.             }
  347.             set pos [nextLineStart $pos]
  348.         }    
  349.     } else {
  350.         # old style header
  351.         set pos [lineStart $pos]
  352.         replaceText $pos [nextLineStart $pos] ""
  353.     }
  354.     # Now pos is at the start of the line where we wish to insert
  355.     goto $pos
  356.     elec::Insertion "${begin} [file::paddedDate] $user(author_initials) •• ••\r"
  357.     message "Pop position to return to where you were."
  358.     return ""
  359. }
  360.  
  361. proc file::paddedDate {{when ""}} {
  362.     if {$when == ""} { set when [now] }
  363.     return [string range "[lindex [mtime $when short] 0]     " 0 7]
  364. }
  365.  
  366. proc file::created {{convert 1}} {
  367.     if [catch {getFileInfo [win::Current] info}] {
  368.         if $convert {
  369.             return [mtime [now]]
  370.         } else {
  371.             return [now]
  372.         }
  373.     } else {
  374.         if $convert {
  375.             return [mtime $info(created)]
  376.         } else {
  377.             return $info(created)
  378.         }
  379.     }        
  380. }
  381.  
  382.  
  383. ## 
  384.  # -------------------------------------------------------------------------
  385.  #     
  386.  #    "file::createHeader" --
  387.  #    
  388.  #     Insert    a descriptive header into the current file.     Needs to be tailored 
  389.  #     more to different modes, but isn't    too    bad    right now.
  390.  #     
  391.  #     'forcemode' will force    the    file into that mode    via    emacs-like mode
  392.  #     entries on    the    top    line of    the    file. 
  393.  #     
  394.  #     'parent' gives    the    name of    a class    from which the generated file
  395.  #     descends (appropriate for C++,    [incr Tcl] for example).
  396.  # 
  397.  # -------------------------------------------------------------------------
  398.  ##
  399. proc file::createHeader { {template ""} {parent "" } } {
  400.     # Make sure the current project is compatible with this mode
  401.     file::coordinateProjectForMode
  402.     if {$parent == ""} {set parent "•parent•"}
  403.     if {$template == ""} { set template [list "" "" "Header" "\#" "" ""] }
  404.     # make the header
  405.     if {[lindex $template 1] != "Empty" } {
  406.         set t ""
  407.         set class [file::className]
  408.         if {$class == "Untitled"} {set class "•class name•"}
  409.         set file [win::CurrentTail]
  410.         set docHeadType [lindex $template 2]
  411.         if {$docHeadType != "None" } {
  412.             append t [file::topHeader]
  413.             if {$docHeadType != "Basic"} {
  414.                 if {$docHeadType == "Source" || [file::isSource $file]} {
  415.                     # it's a source file
  416.                     append t " See header file for further information\r"
  417.                 } elseif {$docHeadType == "Header" || $docHeadType == "*" && [file::isHeader $file]} {
  418.                     global user
  419.                     append t " Description: \r"
  420.                     append t "\r"
  421.                     append t " History\r"
  422.                     append t "\r"
  423.                     append t " modified by  rev reason\r"
  424.                     append t " -------- --- --- -----------\r"
  425.                     append t " [file::paddedDate [file::created 0]] $user(author_initials) 1.0 original\r"
  426.                 } else {
  427.                     # not header or source or basic... oh well!
  428.                 }
  429.             }
  430.             append t "###################################################################"
  431.             set t [file::commentTextBlock $t]
  432.             global mode
  433.             regsub "\r" $t "-*-${mode}-*-\r" t
  434.         }
  435.         set procName [lindex $template 3]
  436.         if {$procName != "\#" && [info commands $procName] == ""} { 
  437.             global PREFS
  438.             if [catch {uplevel \#0 source \{$PREFS:prefs.tcl\}}] {
  439.                 alertnote "An error occurred while loading \"prefs.tcl\"" 
  440.                 global errorInfo
  441.                 dumpTraces "prefs.tcl error" $errorInfo
  442.                 error ""
  443.             }            
  444.         }
  445.         if [catch {append t [eval $procName [list $class] [list $parent] [lindex $template 5]]}] {
  446.             alertnote "An error occurred while calling \"$procName\"" 
  447.             global errorInfo
  448.             dumpTraces "$procName error" $errorInfo
  449.             error ""
  450.         }
  451.         goto 0
  452.         elec::Insertion $t
  453.     }
  454.     return ""
  455. }
  456.  
  457. ## 
  458.  # -------------------------------------------------------------------------
  459.  #     
  460.  #    "file::createDocument" --
  461.  #    
  462.  #     Make a new document from a given template type.
  463.  #     
  464.  #     'forcemode' will force    the    file into that mode    via    emacs-like mode
  465.  #     entries on    the    top    line of    the    file. 
  466.  #     
  467.  # -------------------------------------------------------------------------
  468.  ##
  469. proc file::createDocument { {winCreate ""} {forcemode "" } } {
  470.     # pick a template
  471.     # if [fileIsHeader    $file]
  472.     global elec::DocTemplates mode DocprojmodeVars
  473.     # decide if its mode-specific or not
  474.     set f [lindex $winCreate 2]
  475.     if $DocprojmodeVars(docTemplatesModeSpecific) {
  476.         if {$forcemode != ""} {
  477.             set tlist [file::docTemplates $f $forcemode non]
  478.         } else {
  479.             set tlist [file::docTemplates $f $mode non]
  480.         }
  481.     } else {
  482.         set tlist [file::docTemplates $f "" non]
  483.     }
  484.     lappend tlist "<Create new document type>"
  485.     if {$non != ""} {
  486.         eval lappend tlist "----------------------------------------------------" [lsort $non]
  487.     }
  488.     set tchoice [listpick -p "Pick a document template to insert" -L "Default" $tlist]
  489.     if {$tchoice == "<Create new document type>"} {
  490.         set tchoice [file::newDocumentTemplate 1]
  491.     }
  492.     if {$tchoice == "----------------------------------------------------"} { error "" }
  493.     
  494.     set tinfo [file::docTemplateInfo $tchoice]
  495.     set subTypes [lindex $tinfo 5]
  496.     if {$subTypes != ""} {
  497.         # replace the list of options with just the one selected
  498.         set tinfo [lreplace $tinfo 5 5 [listpick -p "Pick a document subtype of $tchoice" $subTypes]]
  499.     }
  500.     if {$forcemode == "" && [lindex $tinfo 0] != "*"} {
  501.         set forcemode [lindex $tinfo 0]
  502.     }
  503.     if {$winCreate != ""} {
  504.         eval $winCreate
  505.     }
  506.     
  507.     if { $forcemode != "" && $mode != $forcemode} { 
  508.         changeMode $forcemode
  509.     }
  510.     # we need to do this to stop modes switching later if this file isn't
  511.     # obviously a '$mode' file.
  512.     global win::Modes
  513.     set win::Modes($f) $mode
  514.     # set the project
  515.     Docproj::changeProject [lindex $tinfo 4]
  516.     # if the current project doesn't like this mode, then switch
  517.     file::coordinateProjectForMode
  518.     return $tinfo
  519. }
  520.  
  521. proc file::docTemplates { {f ""} {modeSpecific ""} {other ""}} {
  522.     global elec::DocTemplates
  523.     if {$other != ""} { upvar $other noList }
  524.     set tlist ""
  525.     set noList ""
  526.     if {$f != "" && $f != "Untitled"} {
  527.         set m [file::whichModeForWin $f]
  528.         foreach t ${elec::DocTemplates} {
  529.             if [file::docTemplateMatchExt $t $f $m] {
  530.                 lappend tlist [lindex $t 1]
  531.             } else {
  532.                 lappend noList [lindex $t 1]
  533.             }
  534.         }        
  535.     } else {
  536.         foreach t ${elec::DocTemplates} {
  537.             if {$modeSpecific == "" || [string match [lindex $t 0] $modeSpecific]} {
  538.                 lappend tlist [lindex $t 1]
  539.             } else {
  540.                 lappend noList [lindex $t 1]
  541.             }
  542.         }        
  543.     }    
  544.     return [lsort $tlist]
  545. }
  546.  
  547. proc file::docTemplateMatchExt {t f {m ""}} {
  548.     if {$m == ""} {set m [file::whichModeForWin $f]}
  549.     # match everything to a file with no particular extension
  550.     if {$m == "Text"} { return 1 }
  551.     set l [lindex $t 0]
  552.     set mMatch [expr [lsearch -exact $l $m] != -1]
  553.     switch [lindex $t 2] {
  554.         "None" -
  555.         "Basic" -
  556.         "*" {
  557.             if {$l == "*"} {
  558.                 return 1
  559.             } else {
  560.                 return $mMatch
  561.             }
  562.         }
  563.         "Header" {
  564.             if {$mMatch} {
  565.                 return [file::isHeader $f $m]
  566.             }
  567.         }
  568.         "Source" {
  569.             if {$mMatch} {
  570.                 return [file::isSource $f $m]
  571.             }
  572.             
  573.         }
  574.     }
  575.     return 0
  576. }
  577.  
  578. proc file::docTemplateInfo {name} {
  579.     global elec::DocTemplates
  580.     foreach t ${elec::DocTemplates} {
  581.         if {$name == [lindex $t 1]} {
  582.             return $t
  583.         }
  584.     }
  585. }
  586. proc file::docTemplateIndex {name} {
  587.     set i 0
  588.     global elec::DocTemplates
  589.     foreach t ${elec::DocTemplates} {
  590.         if {$name == [lindex $t 1]} {
  591.             return $i
  592.         }
  593.         incr i
  594.     }
  595. }
  596.  
  597. proc file::notTextMode {} {
  598.     global mode modeMenus
  599.     if { $mode == "Text" } {
  600.         # we probably don't want Text mode     
  601.         set m [listpick -p "Pick a mode:" -L "Text" [array names modeMenus]]
  602.         if { $m == "" } {set m "Text"}
  603.         changeMode $m
  604.     } 
  605. }
  606.  
  607. ## 
  608.  # -------------------------------------------------------------------------
  609.  #     
  610.  #    "file::topHeader"    --
  611.  #    
  612.  #     Inserts the top part of a    descriptive    header into    the    current    file
  613.  # -------------------------------------------------------------------------
  614.  ##
  615. proc file::topHeader { } {
  616.     global user
  617.     set file [win::CurrentTail]
  618.     if [catch {getFileInfo [win::Current] info}] {
  619.         set created [mtime [now]]
  620.         set last_update $created
  621.     } else {
  622.         set created [mtime $info(created)]
  623.         set last_update [mtime $info(modified)]
  624.     }        
  625.     append t "###################################################################\r"
  626.     if {[file::projectName] != "*"} {
  627.         append t " [file::projectName] - [file::projectAddendum]\r"
  628.     }
  629.     append t "\r" 
  630.     append t " FILE: \"" $file "\"\r"
  631.     append t "                                   created: $created \r"
  632.     append t "                               last update: $last_update \r"    
  633.     append t " Author: $user(author)\r"
  634.     append t " E-mail: $user(email)\r"
  635.     if {$user(organisation) != ""} {
  636.         append t "   mail: $user(organisation)\r"
  637.     }
  638.     if {$user(address) != ""} {
  639.         append t "         $user(address)\r"
  640.     }
  641.     if {$user(www) != ""} {
  642.         append t "    www: $user(www)\r"
  643.     }
  644.     append t " \r"
  645.     append t [file::[file::projectLicense]]
  646.     if {[set e [file::projectExtra]] != ""} {
  647.         append t "[breakIntoLines $e]\r \r"
  648.     }
  649.     return $t
  650. }
  651.  
  652. ## 
  653.  # -------------------------------------------------------------------------
  654.  #     
  655.  #    "file::className"    --
  656.  #    
  657.  #     Extract root of file name as a    class name for the file    (obviously most    
  658.  #     relevant to C++)  
  659.  # -------------------------------------------------------------------------
  660.  ##
  661. proc file::className {} { return [file::baseName [win::CurrentTail]] }
  662.  
  663.  
  664. ## 
  665.  # -------------------------------------------------------------------------
  666.  #   
  667.  #  "file::coordinateProjectForMode" --
  668.  #  
  669.  #   When we create a new file or header automatically, it contains
  670.  #   information about our current project (as defined in docProject(...)).
  671.  #   Unfortunately we often forget to select the correct project first.
  672.  #   This procedure makes sure that your project is compatible with the
  673.  #   current mode, given the information in the 'docProject' array. If it isn't
  674.  #   then the current project is changed if a better match can be found. 
  675.  #         
  676.  #  Results:
  677.  #   None
  678.  #  
  679.  #  Side effects:
  680.  #   The current project may be changed
  681.  # -------------------------------------------------------------------------
  682.  ##
  683. proc file::coordinateProjectForMode {} {
  684.     global mode docProject
  685.     set currProj [file::projectName]
  686.     set projModes [lindex $docProject(default_modes) \
  687.         [lsearch -exact $docProject(name) [file::projectName]]]
  688.     if { $projModes != "" && [lsearch -exact $projModes $mode] == -1 } {
  689.         # this project doesn't like this mode.
  690.         # see if there's a better one
  691.         foreach modeLists $docProject(default_modes) {
  692.             if { [lsearch -exact $modeLists $mode] != -1 } {
  693.                 # found a fit
  694.                 set index [lsearch -exact $docProject(default_modes) $modeLists]
  695.                 set proj [lindex $docProject(name) $index]
  696.                 Docproj::changeProject "$proj"
  697.                 return
  698.             }
  699.         }
  700.     }
  701. }
  702.  
  703. proc file::createNewClass {} {
  704.     global mode
  705.     # if the current project doesn't like this mode, then switch
  706.     file::coordinateProjectForMode
  707.     beep
  708.     set class [statusPrompt "A name for the new class:"]
  709.     set parent [statusPrompt "Descended from:" ]
  710.     switch $mode {
  711.         "C" -
  712.         "C++" {
  713.             file::createHeader [file::createDocument "new -n ${class}.cc" C++] $parent
  714.             file::createHeader [file::createDocument "new -n ${class}.h" C++] $parent
  715.         } 
  716.         "Tcl" {
  717.             file::createHeader [file::createDocument "new -n ${class}.tcl" Tcl] $parent
  718.         }
  719.         default {
  720.             message "No class procedure defined for your mode. Why not write one yourself?"
  721.         }
  722.         
  723.     }            
  724.             
  725. }
  726.  
  727.  
  728. ## 
  729.  # -------------------------------------------------------------------------
  730.  #   
  731.  # "file::updateGeneralDate" --
  732.  #  
  733.  #  Updates the date in the header of a file.  Normally this is the 
  734.  #  'last update' date, but we can override that if desired.
  735.  # -------------------------------------------------------------------------
  736.  ##
  737. proc file::updateGeneralDate { name {patt ""} {time ""}} {
  738.     if {$patt == ""} {set patt {last update: }}
  739.     regsub -all { } $patt {[ \t]} spatt
  740.     set pos [getPos]
  741.     set end [selEnd]
  742.     set hour {[0-9][0-9]?(:|\.)[0-9][0-9]((:|\.)[0-9][0-9])?([ \t][APap][Mm])?}
  743.     set date {[0-9][0-9]?(/|\.|\-)[0-9][0-9]?(/|\.|\-)[0-9][0-9]([0-9][0-9])?}
  744.     append spatt {[ \t]*} $date {[ \t]\{?} $hour {\}?}
  745.     if [catch {search -s -f 1 -r 1 -m 0 -l 1000 $spatt 0} datePos] {return}
  746.     if {$time == ""} {set time [mtime [now] short]}
  747.     if {[eval getText $datePos] == $time} {return}
  748.     eval replaceText $datePos [list $patt $time]
  749.     select $pos $end
  750.     return
  751. }
  752.  
  753. proc file::updateDate { {name ""} } {
  754.     set fr [win::Current]
  755.     if { $name == "" } {
  756.         set name $fr
  757.     }
  758.     if { $name != $fr } {
  759.         bringToFront $name
  760.         file::updateGeneralDate $name
  761.         bringToFront $fr
  762.     } else {
  763.         file::updateGeneralDate $name
  764.     }    
  765. }
  766.  
  767. proc file::updateCreationDate { name } {
  768.     if [catch {getFileInfo [stripNameCount [win::Current]] info}] {
  769.         set created [mtime [now]]
  770.     } else {
  771.         set created [mtime $info(created)]
  772.     }        
  773.     file::updateGeneralDate $name "created" $created
  774. }
  775.  
  776. proc file::newFunction {} {
  777.     elec::Insertion "[file::className]::•name•(•args•){\r\t•body•\r}\r"
  778. }
  779.  
  780. proc global::newDocumentTemplate { {subCall 0} } {
  781.     set newT [global::_editDocumentTemplate]
  782.     global elec::DocTemplates 
  783.     lappend elec::DocTemplates $newT
  784.     # save it permanently
  785.     global modifiedVars
  786.     lappend modifiedVars elec::DocTemplates
  787.     # add template to "prefs.tcl"
  788.     set procedure [lindex $newT 3]
  789.     set subproj [lindex $newT 5]
  790.     if {$procedure != "\#"} {
  791.         set def [file::_getDefault "Do you want to use this as the template?"]
  792.         set t "\r"
  793.         append t "proc $procedure \{docname parentdoc"
  794.         if {$subproj != ""} { append t " subtype " }
  795.         append t "\} \{\r"
  796.         append t "\t# You must fill this in\r"
  797.         if {$subproj != ""} { append t "\t# Possible 'subtypes' are: $subproj\r" }
  798.         append t $def
  799.         append t "\r\treturn \$t\r\}\r"
  800.         addUserLine $t
  801.         if {[askyesno "I've added a template for the procedure to your 'prefs.tcl'. Do you want to edit it now?"] == "yes"} {
  802.             global::editPrefsFile
  803.             goto [maxPos]
  804.             if $subCall { 
  805.                 alertnote "Once you've finished editing, hit cmd-N to go back and create a new document." 
  806.                 # so our calling proc stops
  807.                 error "Editing"
  808.             }
  809.         }
  810.     }
  811.     return [lindex $newT 1]
  812. }
  813.  
  814. proc file::_varValue {var} {
  815.     upvar $var a
  816.     if [info exists a] {
  817.         return $a
  818.     } else {
  819.         return ""
  820.     }
  821. }
  822.  
  823. proc file::_getDefault { text {default ""} {var "t"}} {
  824.     if [isSelection] {
  825.         if {[askyesno "I notice you've selected some text. $text"] == "yes"} {
  826.             set default [getSelect]
  827.         } 
  828.     }
  829.     if {$default == ""} {
  830.         set default [getline "Enter template text (you can edit it later)" $default]
  831.     }
  832.     return [elec::_MakeIntoInsertion $default $var]
  833. }
  834.  
  835. proc global::_editDocumentTemplate {{def ""}} {
  836.     global DocprojmodeVars
  837.     if {$def == ""} {
  838.         set title "Create a new document template" 
  839.         set def {"" "" "By File Extension" "t_XXX" $DocprojmodeVars(currentProject) ""}
  840.         set new 1
  841.     } else {
  842.         set title "Edit document template" 
  843.         set new 0
  844.     }
  845.     
  846.     global docProject
  847.     set name ""
  848.     while { $name == ""} {
  849.         set y 40
  850.         set yb 220
  851.         set res [eval dialog -w 380 -h 340 \
  852.         [dialog::title $title 380] \
  853.         [dialog::button "OK" 290 yb] \
  854.         [dialog::button "Cancel" 290 yb] \
  855.         [dialog::textedit "Descriptive Name" [lindex $def 1] 10 y 15] \
  856.         [dialog::textedit "Modes (blank = all)" [lindex $def 0] 10 y 15] \
  857.         [dialog::textedit "Procedure name" [lindex $def 3] 10 y 15] \
  858.         [dialog::text "Descriptive header for this document template" 10 y] \
  859.         [dialog::text "(if 'Source', or 'Header', the mode must define" 10 y] \
  860.         [dialog::text "headerSuffices and sourceSuffices vars)" 10 y] \
  861.         [dialog::menu 10 y [list "None" "-" "Basic" "Source" "Header" "Either"] [lindex $def 2]] \
  862.         [dialog::text "Project name" 10 y] \
  863.         [dialog::menu 10 y $docProject(name) [lindex $def 4]] \
  864.         [dialog::textedit "List of sub-types" [lindex $def 5] 10 y 30] \
  865.         ]
  866.         if [lindex $res 1] { error "Cancel" } 
  867.         set i 1
  868.         foreach var {name modes procedure filetype proj subproj} {
  869.             set $var [lindex $res [incr i]]
  870.         }
  871.         if {$name == ""} { beep ; message "You must enter a name." }
  872.     }    
  873.     if {$modes == ""} {set modes "*"}
  874.     if {$filetype == "Either"} {set filetype "*"}
  875.     if {$proj == "None"} {set proj "*"}
  876.     if {$procedure == ""} {set procedure "\#"}
  877.     return [list $modes $name $filetype $procedure $proj $subproj]
  878.     
  879. }
  880.  
  881. proc global::editDocumentTemplate {} {
  882.     global modifiedVars elec::DocTemplates
  883.     set tlist [file::docTemplates] 
  884.     set l [listpick -p "Which document template do you want to edit?" $tlist]
  885.     set lind [file::docTemplateIndex $l]
  886.     set l [global::_editDocumentTemplate [file::docTemplateInfo $l]]
  887.     set elec::DocTemplates [lreplace ${elec::DocTemplates} $lind $lind $l]
  888.     lappend modifiedVars elec::DocTemplates
  889. }
  890.  
  891. proc global::removeDocumentTemplate {} {
  892.     global modifiedVars elec::DocTemplates
  893.     set tlist [file::docTemplates] 
  894.     set l [listpick -p "Which document template shall I permanently remove?" $tlist]
  895.     set l [file::docTemplateIndex $l]
  896.     set elec::DocTemplates [lreplace ${elec::DocTemplates} $l $l]
  897.     lappend modifiedVars elec::DocTemplates
  898. }
  899.  
  900. ## Create this sort of stuff.
  901.  # set docProject(name) [list    "None" "EvoX" "Vince's Additions" "Cpptcl"]
  902.  # set docProject(addendum) {    {none} {evolution in complex systems} \
  903.  #       {an extension package for Alpha}    {connecting    C++    with Tcl} }
  904.  # set docProject(default_modes) { {}    {C C++}    {Tcl} {C C++ Tcl}}
  905.  ##
  906. proc global::newProject {} {
  907.     global docProject
  908.     set res [global::_editProject]
  909.     set i -1
  910.     foreach var {name addendum license extra default_modes} {
  911.         lappend docProject($var) [lindex $res [incr i]]
  912.     }
  913.     global modifiedArrVars
  914.     lappend modifiedArrVars docProject
  915.     addMenuItem -m {Current Project} [lindex $res 0]
  916.     Docproj::changeProject [lindex $res 0]
  917. }
  918. proc global::_editProject {{def ""}} {
  919.     if {$def == ""} {
  920.         set title "Create a new project"
  921.         set def [list "Vince's Additions" "an extension package for Alpha" "license.terms" "See the file \"license.terms\" for information on usage and redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES." ""]
  922.     } else {
  923.         set title "Edit a project"
  924.     }
  925.     set y 40
  926.     set yb 270
  927.     global elec::LicenseTemplates
  928.     set res [eval dialog -w 380 -h 325 \
  929.     [dialog::title $title 360] \
  930.     [dialog::button "OK" 290 yb] \
  931.     [dialog::button "Cancel" 290 yb] \
  932.     [dialog::textedit "Short Descriptive Name" [lindex $def 0] 10 y 15] \
  933.     [dialog::textedit "Longer Description to append to the above" [lindex $def 1] 10 y 25] \
  934.     [dialog::text "License type for header comments" 10 y] \
  935.     [dialog::menu 10 y ${elec::LicenseTemplates} [lindex $def 2]] \
  936.     [dialog::textedit "Additional text for end of header comments" [lindex $def 3] 10 y 35 5] \
  937.     [dialog::textedit "Modes (blank = all)" [lindex $def 4] 10 y 15] \
  938.     ]
  939.     if [lindex $res 1] { error "Cancel" }
  940.     return [lrange $res 2 6]    
  941. }
  942.  
  943. proc global::editProject {} {
  944.     global docProject modifiedArrVars
  945.     set l [listpick -p "Which project do you wish to edit?" \
  946.         -L [file::projectName] $docProject(name)]
  947.     set item [lsearch -exact $docProject(name) $l]
  948.     foreach uvar {name addendum license extra default_modes} {
  949.         lappend def [lindex $docProject($uvar) $item]
  950.     }
  951.     set def [global::_editProject $def]
  952.     set i -1
  953.     foreach uvar {name addendum license extra default_modes} {
  954.         set docProject($uvar) [lreplace $docProject($uvar) $item $item [lindex $def [incr i]]]
  955.     }
  956.     lappend modifiedArrVars docProject
  957. }
  958.  
  959. proc global::removeProject {} {
  960.     global docProject modifiedArrVars
  961.     set l [listpick -p "Which project shall I permanently remove?" $docProject(name)]
  962.     set item [lsearch -exact $docProject(name) $l]
  963.     foreach uvar {name addendum license extra default_modes} {
  964.         set docProject($uvar) [lreplace $docProject($uvar) $item $item]
  965.     }
  966.     lappend modifiedArrVars docProject
  967.     if {[file::projectName] == $l} {
  968.         Docproj::changeProject "None"
  969.     }
  970.     deleteMenuItem -m {Current Project} $l
  971. }
  972.  
  973.